//the test include 2 parts : write / read & search.
module tlb_top #
(
    parameter TLBNUM = 16,
    parameter PALEN = 32,
    parameter SIMULATION = 1'b0
)
(
    input         resetn, 
    input         clk,

    //------gpio-------
    output [15:0] led,
    output reg [7 :0] num_csn,
    output reg [6 :0] num_a_g
);

clk_pll clk_pll(
    .clk_out1(clk_g),
    .clk_in1(clk)
);

reg       test_error;
reg       tlb_w_test_ok;
reg       tlb_r_test_ok;
reg       tlb_s_test_ok;
reg [3:0] tlb_w_cnt;
reg [3:0] tlb_r_cnt;
reg [3:0] tlb_s_cnt;

// search port 0
wire [19:0]                 s0_va_31_12;
wire [9:0]                  s0_asid;
wire                        s0_found;
wire [$clog2(TLBNUM)-1:0]   s0_index;
wire [PALEN - 13 : 0]       s0_ppn;
wire [1:0]                  s0_plv;
wire [1:0]                  s0_mat;
wire                        s0_d;
wire                        s0_v;
// search port 1
wire [19:0]                 s1_va_31_12;
wire [9:0]                  s1_asid;
wire                        s1_found;
wire [$clog2(TLBNUM)-1:0]   s1_index;
wire [PALEN - 13 : 0]       s1_ppn;
wire [1:0]                  s1_plv;
wire [1:0]                  s1_mat;
wire                        s1_d;
wire                        s1_v;
// write port
wire                        we;
wire [$clog2(TLBNUM)-1:0]   w_index;
wire [18:0]                 w_vppn;
wire [5:0]                  w_ps;
wire                        w_g;
wire [9:0]                  w_asid;
wire                        w_e;
wire [PALEN - 13 : 0]       w_ppn0;
wire [1:0]                  w_plv0;
wire [1:0]                  w_mat0;
wire                        w_d0;
wire                        w_v0;
wire [PALEN - 13 : 0]       w_ppn1;
wire [1:0]                  w_plv1;
wire [1:0]                  w_mat1;
wire                        w_d1;
wire                        w_v1;
// read port
wire [$clog2(TLBNUM)-1:0]   r_index;
wire [18:0]                 r_vppn;
wire [5:0]                  r_ps;
wire                        r_g;
wire [9:0]                  r_asid;
wire                        r_e;
wire [PALEN - 13 : 0]       r_ppn0;
wire [1:0]                  r_plv0;
wire [1:0]                  r_mat0;
wire                        r_d0;
wire                        r_v0;
wire [PALEN - 13 : 0]       r_ppn1;
wire [1:0]                  r_plv1;
wire [1:0]                  r_mat1;
wire                        r_d1;
wire                        r_v1;

wire        r_error;
wire        s0_error;
wire        s1_error;
wire        wait_1s;

//wait_1s
reg [26:0] wait_cnt;
assign wait_1s = wait_cnt==27'd0;
always @(posedge clk_g)
begin
    if (!resetn ||  wait_1s)
    begin
        wait_cnt <= (SIMULATION == 1'b1) ? 27'd5 : 27'd30_000_000;
    end
    else
    begin
        wait_cnt <= wait_cnt - 1'b1;
    end
end
tlb #(.TLBNUM(16)) tlb
(
    .clk(clk_g),
    .s0_va_31_12(s0_va_31_12),
    .s0_asid(s0_asid),
    .s0_found(s0_found),
    .s0_index(s0_index),
    .s0_ppn(s0_ppn),
    .s0_plv(s0_plv),
    .s0_mat(s0_mat),
    .s0_d(s0_d),
    .s0_v(s0_v),
    .s1_va_31_12(s1_va_31_12),
    .s1_asid(s1_asid),
    .s1_found(s1_found),
    .s1_index(s1_index),
    .s1_ppn(s1_ppn),
    .s1_plv(s1_plv),
    .s1_mat(s1_mat),
    .s1_d(s1_d),
    .s1_v(s1_v),
    .we(we),
    .w_index(w_index),
    .w_vppn(w_vppn),
    .w_ps(w_ps),
    .w_g(w_g),
    .w_asid(w_asid),
    .w_e(w_e),
    .w_ppn0(w_ppn0),
    .w_plv0(w_plv0),
    .w_mat0(w_mat0),
    .w_d0(w_d0),
    .w_v0(w_v0),
    .w_ppn1(w_ppn1),
    .w_plv1(w_plv1),
    .w_mat1(w_mat1),
    .w_d1(w_d1),
    .w_v1(w_v1),
    .r_index(r_index),
    .r_vppn(r_vppn),
    .r_ps(r_ps),
    .r_g(r_g),
    .r_asid(r_asid),
    .r_e(r_e),
    .r_ppn0(r_ppn0),
    .r_plv0(r_plv0),
    .r_mat0(r_mat0),
    .r_d0(r_d0),
    .r_v0(r_v0),
    .r_ppn1(r_ppn1),
    .r_plv1(r_plv1),
    .r_mat1(r_mat1),
    .r_d1(r_d1),
    .r_v1(r_v1),
);

// input data
// write \ read

// index |  vppn  | ps | asid | e | g |  ppn0  | plv0 mat0 d0 v0 |  ppn1  | plv1 mat1 d1 v1 |
//   0   | 0x0000 | 12 |  0x0 | 1 | 0 | 0x1111 |     3,1,1,1     | 0x2022 |     3,1,1,1     |
//   1   | 0x1111 | 12 |  0x1 | 1 | 1 | 0x2222 |     3,1,1,1     | 0x3033 |     3,1,1,0     |
//   2   | 0x2222 | 12 |  0x2 | 0 | 0 | 0x3333 |     3,1,1,0     | 0x4044 |     3,1,1,1     |
//   3   | 0x3333 | 12 |  0x3 | 0 | 1 | 0x4444 |     3,1,1,0     | 0x5055 |     3,1,1,0     |
//   4   | 0x4444 | 22 |  0x4 | 0 | 0 | 0x5555 |     3,1,1,1     | 0x6066 |     3,1,1,1     |
//   5   | 0x5555 | 22 |  0x5 | 0 | 1 | 0x6666 |     3,1,1,1     | 0x7077 |     3,1,1,0     |
//   6   | 0x6666 | 22 |  0x6 | 1 | 0 | 0x7777 |     3,1,1,0     | 0x8088 |     3,1,1,1     |
//   7   | 0x7777 | 22 |  0x7 | 1 | 1 | 0x8888 |     3,1,1,0     | 0x9099 |     3,1,1,0     |
//   8   | 0x8888 | 12 |  0x8 | 1 | 0 | 0x9999 |     3,1,1,1     | 0xa0aa |     3,1,1,1     |
//   9   | 0x8888 | 12 |  0x8 | 0 | 0 | 0xaaaa |     3,1,1,1     | 0xb0bb |     3,1,1,0     |
//   10  | 0x8889 | 12 |  0x8 | 1 | 0 | 0xbbbb |     3,1,1,0     | 0xc0cc |     3,1,1,1     |
//   11  | 0x8888 | 12 |  0xb | 1 | 0 | 0xcccc |     3,1,1,0     | 0xd0dd |     3,1,1,0     |
//   12  | 0x8888 | 22 |  0xc | 1 | 0 | 0xdddd |     3,1,1,1     | 0xe0ee |     3,1,1,1     |
//   13  | 0x8888 | 22 |  0x8 | 0 | 0 | 0xeeee |     3,1,1,1     | 0xf0ff |     3,1,1,0     |
//   14  | 0xeeee | 22 |  0x8 | 1 | 0 | 0xffff |     3,1,1,0     | 0x0000 |     3,1,1,1     |
//   15  | 0xffff | 22 |  0xf | 1 | 1 | 0x0000 |     3,1,1,0     | 0x1011 |     3,1,1,0     |

wire [18:0]             tlb_vppn [15:0];
wire [5:0]              tlb_ps   [15:0];
wire                    tlb_g    [15:0];
wire [9:0]              tlb_asid [15:0];
wire                    tlb_e    [15:0];
wire [PALEN - 13 : 0]   tlb_ppn0 [15:0];
wire [1:0]              tlb_plv0 [15:0];
wire [1:0]              tlb_mat0 [15:0];
wire                    tlb_d0   [15:0];
wire                    tlb_v0   [15:0];
wire [PALEN - 13 : 0]   tlb_ppn1 [15:0];
wire [1:0]              tlb_plv1 [15:0];
wire [1:0]              tlb_mat1 [15:0];
wire                    tlb_d1   [15:0];
wire                    tlb_v1   [15:0];

//TODO :update
assign tlb_vppn[ 0] = 23'h0x0000;
assign tlb_vppn[ 1] = 23'h0x1111;
assign tlb_vppn[ 2] = 23'h0x2222;
assign tlb_vppn[ 3] = 23'h0x3333;
assign tlb_vppn[ 4] = 23'h0x4444;
assign tlb_vppn[ 5] = 23'h0x5555;
assign tlb_vppn[ 6] = 23'h0x6666;
assign tlb_vppn[ 7] = 23'h0x7777;
assign tlb_vppn[ 8] = 23'h0x8888;
assign tlb_vppn[ 9] = 23'h0x8888;
assign tlb_vppn[10] = 23'h0x8889;
assign tlb_vppn[11] = 23'h0x8888;
assign tlb_vppn[12] = 23'h0x8888;
assign tlb_vppn[13] = 23'h0x8888;
assign tlb_vppn[14] = 23'h0xeeee;
assign tlb_vppn[15] = 23'h0xffff;

assign tlb_ps[ 0] = 6'd12;
assign tlb_ps[ 1] = 6'd12;
assign tlb_ps[ 2] = 6'd12;
assign tlb_ps[ 3] = 6'd12;
assign tlb_ps[ 4] = 6'd22;
assign tlb_ps[ 5] = 6'd22;
assign tlb_ps[ 6] = 6'd22;
assign tlb_ps[ 7] = 6'd22;
assign tlb_ps[ 8] = 6'd12;
assign tlb_ps[ 9] = 6'd12;
assign tlb_ps[10] = 6'd12;
assign tlb_ps[11] = 6'd12;
assign tlb_ps[12] = 6'd22;
assign tlb_ps[13] = 6'd22;
assign tlb_ps[14] = 6'd22;
assign tlb_ps[15] = 6'd22;

assign tlb_asid[ 0] = 8'h0;
assign tlb_asid[ 1] = 8'h1;
assign tlb_asid[ 2] = 8'h2;
assign tlb_asid[ 3] = 8'h3;
assign tlb_asid[ 4] = 8'h4;
assign tlb_asid[ 5] = 8'h5;
assign tlb_asid[ 6] = 8'h6;
assign tlb_asid[ 7] = 8'h7;
assign tlb_asid[ 8] = 8'h8;
assign tlb_asid[ 9] = 8'h8;
assign tlb_asid[10] = 8'h8;
assign tlb_asid[11] = 8'hb;
assign tlb_asid[12] = 8'hc;
assign tlb_asid[13] = 8'h8;
assign tlb_asid[14] = 8'h8;
assign tlb_asid[15] = 8'hf;

assign tlb_e[ 0] = 1'h1;
assign tlb_e[ 1] = 1'h1;
assign tlb_e[ 2] = 1'h0;
assign tlb_e[ 3] = 1'h0;
assign tlb_e[ 4] = 1'h0;
assign tlb_e[ 5] = 1'h0;
assign tlb_e[ 6] = 1'h1;
assign tlb_e[ 7] = 1'h1;
assign tlb_e[ 8] = 1'h1;
assign tlb_e[ 9] = 1'h0;
assign tlb_e[10] = 1'h1;
assign tlb_e[11] = 1'h1;
assign tlb_e[12] = 1'h1;
assign tlb_e[13] = 1'h0;
assign tlb_e[14] = 1'h1;
assign tlb_e[15] = 1'h1;

assign tlb_g[ 0] = 1'h0;
assign tlb_g[ 1] = 1'h1;
assign tlb_g[ 2] = 1'h0;
assign tlb_g[ 3] = 1'h1;
assign tlb_g[ 4] = 1'h0;
assign tlb_g[ 5] = 1'h1;
assign tlb_g[ 6] = 1'h0;
assign tlb_g[ 7] = 1'h1;
assign tlb_g[ 8] = 1'h0;
assign tlb_g[ 9] = 1'h0;
assign tlb_g[10] = 1'h0;
assign tlb_g[11] = 1'h0;
assign tlb_g[12] = 1'h0;
assign tlb_g[13] = 1'h0;
assign tlb_g[14] = 1'h0;
assign tlb_g[15] = 1'h1;

assign tlb_ppn0[ 0] = 24'h1111;
assign tlb_ppn0[ 1] = 24'h2222;
assign tlb_ppn0[ 2] = 24'h3333;
assign tlb_ppn0[ 3] = 24'h4444;
assign tlb_ppn0[ 4] = 24'h5555;
assign tlb_ppn0[ 5] = 24'h6666;
assign tlb_ppn0[ 6] = 24'h7777;
assign tlb_ppn0[ 7] = 24'h8888;
assign tlb_ppn0[ 8] = 24'h9999;
assign tlb_ppn0[ 9] = 24'haaaa;
assign tlb_ppn0[10] = 24'hbbbb;
assign tlb_ppn0[11] = 24'hcccc;
assign tlb_ppn0[12] = 24'hdddd;
assign tlb_ppn0[13] = 24'heeee;
assign tlb_ppn0[14] = 24'hffff;
assign tlb_ppn0[15] = 24'h0000;

assign tlb_plv0[ 0] = 2'h3;
assign tlb_plv0[ 1] = 2'h3;
assign tlb_plv0[ 2] = 2'h3;
assign tlb_plv0[ 3] = 2'h3;
assign tlb_plv0[ 4] = 2'h3;
assign tlb_plv0[ 5] = 2'h3;
assign tlb_plv0[ 6] = 2'h3;
assign tlb_plv0[ 7] = 2'h3;
assign tlb_plv0[ 8] = 2'h3;
assign tlb_plv0[ 9] = 2'h3;
assign tlb_plv0[10] = 2'h3;
assign tlb_plv0[11] = 2'h3;
assign tlb_plv0[12] = 2'h3;
assign tlb_plv0[13] = 2'h3;
assign tlb_plv0[14] = 2'h3;
assign tlb_plv0[15] = 2'h3;

assign tlb_mat0[ 0] = 2'h1;
assign tlb_mat0[ 1] = 2'h1;
assign tlb_mat0[ 2] = 2'h1;
assign tlb_mat0[ 3] = 2'h1;
assign tlb_mat0[ 4] = 2'h1;
assign tlb_mat0[ 5] = 2'h1;
assign tlb_mat0[ 6] = 2'h1;
assign tlb_mat0[ 7] = 2'h1;
assign tlb_mat0[ 8] = 2'h1;
assign tlb_mat0[ 9] = 2'h1;
assign tlb_mat0[10] = 2'h1;
assign tlb_mat0[11] = 2'h1;
assign tlb_mat0[12] = 2'h1;
assign tlb_mat0[13] = 2'h1;
assign tlb_mat0[14] = 2'h1;
assign tlb_mat0[15] = 2'h1;

assign tlb_d0[ 0] = 1'h1;
assign tlb_d0[ 1] = 1'h1;
assign tlb_d0[ 2] = 1'h1;
assign tlb_d0[ 3] = 1'h1;
assign tlb_d0[ 4] = 1'h1;
assign tlb_d0[ 5] = 1'h1;
assign tlb_d0[ 6] = 1'h1;
assign tlb_d0[ 7] = 1'h1;
assign tlb_d0[ 8] = 1'h1;
assign tlb_d0[ 9] = 1'h1;
assign tlb_d0[10] = 1'h1;
assign tlb_d0[11] = 1'h1;
assign tlb_d0[12] = 1'h1;
assign tlb_d0[13] = 1'h1;
assign tlb_d0[14] = 1'h1;
assign tlb_d0[15] = 1'h1;

assign tlb_v0[ 0] = 1'h1;
assign tlb_v0[ 1] = 1'h1;
assign tlb_v0[ 2] = 1'h0;
assign tlb_v0[ 3] = 1'h0;
assign tlb_v0[ 4] = 1'h1;
assign tlb_v0[ 5] = 1'h1;
assign tlb_v0[ 6] = 1'h0;
assign tlb_v0[ 7] = 1'h0;
assign tlb_v0[ 8] = 1'h1;
assign tlb_v0[ 9] = 1'h1;
assign tlb_v0[10] = 1'h0;
assign tlb_v0[11] = 1'h0;
assign tlb_v0[12] = 1'h1;
assign tlb_v0[13] = 1'h1;
assign tlb_v0[14] = 1'h0;
assign tlb_v0[15] = 1'h0;

assign tlb_ppn1[ 0] = 24'h2022;
assign tlb_ppn1[ 1] = 24'h3033;
assign tlb_ppn1[ 2] = 24'h4044;
assign tlb_ppn1[ 3] = 24'h5055;
assign tlb_ppn1[ 4] = 24'h6066;
assign tlb_ppn1[ 5] = 24'h7077;
assign tlb_ppn1[ 6] = 24'h8088;
assign tlb_ppn1[ 7] = 24'h9099;
assign tlb_ppn1[ 8] = 24'ha0aa;
assign tlb_ppn1[ 9] = 24'hb0bb;
assign tlb_ppn1[10] = 24'hc0cc;
assign tlb_ppn1[11] = 24'hd0dd;
assign tlb_ppn1[12] = 24'he0ee;
assign tlb_ppn1[13] = 24'hf0ff;
assign tlb_ppn1[14] = 24'h0000;
assign tlb_ppn1[15] = 24'h1011;

assign tlb_plv1[ 0] = 2'h3;
assign tlb_plv1[ 1] = 2'h3;
assign tlb_plv1[ 2] = 2'h3;
assign tlb_plv1[ 3] = 2'h3;
assign tlb_plv1[ 4] = 2'h3;
assign tlb_plv1[ 5] = 2'h3;
assign tlb_plv1[ 6] = 2'h3;
assign tlb_plv1[ 7] = 2'h3;
assign tlb_plv1[ 8] = 2'h3;
assign tlb_plv1[ 9] = 2'h3;
assign tlb_plv1[10] = 2'h3;
assign tlb_plv1[11] = 2'h3;
assign tlb_plv1[12] = 2'h3;
assign tlb_plv1[13] = 2'h3;
assign tlb_plv1[14] = 2'h3;
assign tlb_plv1[15] = 2'h3;

assign tlb_mat1[ 0] = 2'h1;
assign tlb_mat1[ 1] = 2'h1;
assign tlb_mat1[ 2] = 2'h1;
assign tlb_mat1[ 3] = 2'h1;
assign tlb_mat1[ 4] = 2'h1;
assign tlb_mat1[ 5] = 2'h1;
assign tlb_mat1[ 6] = 2'h1;
assign tlb_mat1[ 7] = 2'h1;
assign tlb_mat1[ 8] = 2'h1;
assign tlb_mat1[ 9] = 2'h1;
assign tlb_mat1[10] = 2'h1;
assign tlb_mat1[11] = 2'h1;
assign tlb_mat1[12] = 2'h1;
assign tlb_mat1[13] = 2'h1;
assign tlb_mat1[14] = 2'h1;
assign tlb_mat1[15] = 2'h1;

assign tlb_d1[ 0] = 1'h1;
assign tlb_d1[ 1] = 1'h1;
assign tlb_d1[ 2] = 1'h1;
assign tlb_d1[ 3] = 1'h1;
assign tlb_d1[ 4] = 1'h1;
assign tlb_d1[ 5] = 1'h1;
assign tlb_d1[ 6] = 1'h1;
assign tlb_d1[ 7] = 1'h1;
assign tlb_d1[ 8] = 1'h1;
assign tlb_d1[ 9] = 1'h1;
assign tlb_d1[10] = 1'h1;
assign tlb_d1[11] = 1'h1;
assign tlb_d1[12] = 1'h1;
assign tlb_d1[13] = 1'h1;
assign tlb_d1[14] = 1'h1;
assign tlb_d1[15] = 1'h1;

assign tlb_v1[ 0] = 1'h1;
assign tlb_v1[ 1] = 1'h0;
assign tlb_v1[ 2] = 1'h1;
assign tlb_v1[ 3] = 1'h0;
assign tlb_v1[ 4] = 1'h1;
assign tlb_v1[ 5] = 1'h0;
assign tlb_v1[ 6] = 1'h1;
assign tlb_v1[ 7] = 1'h0;
assign tlb_v1[ 8] = 1'h1;
assign tlb_v1[ 9] = 1'h0;
assign tlb_v1[10] = 1'h1;
assign tlb_v1[11] = 1'h0;
assign tlb_v1[12] = 1'h1;
assign tlb_v1[13] = 1'h0;
assign tlb_v1[14] = 1'h1;
assign tlb_v1[15] = 1'h0;

//search
// va[:13]  | va[12]  |  asid  |  found  |  index  |   ppn    |  plv mat d v  |
//  0x0000  |   0x0   |   0x0  |      1  |      0  |  0x1111  |    3,1,1,1    |
//  0x0000  |   0x1   |   0x0  |      1  |      0  |  0x2022  |    3,1,1,1    |
//  0x0000  |   0x1   |   0x1  |      0  |      x  |  0xxxxx  |    x,x,x,x    |
//  0x1111  |   0x1   |   0x0  |      1  |      1  |  0x3033  |    3,1,1,0    |
//  0x1111  |   0x0   |   0x0  |      1  |      1  |  0x2222  |    3,1,1,1    |
//  0x1111  |   0x0   |   0x1  |      1  |      1  |  0x2222  |    3,1,1,1    |
//  0x2222  |   0x0   |   0x2  |      0  |      x  |  0xxxxx  |    x,x,x,x    |
//  0x3333  |   0x0   |   0x3  |      0  |      x  |  0xxxxx  |    x,x,x,x    |
//  0x67ff  |   0x0   |   0x6  |      1  |      6  |  0x8bfe  |    3,1,1,1    |
//  0x6400  |   0x1   |   0x6  |      1  |      6  |  0x7001  |    3,1,1,0    |
//  0x6666  |   0x0   |   0x7  |      0  |      x  |  0xxxxx  |    x,x,x,x    |
//  0x7777  |   0x0   |   0x0  |      1  |      7  |  0x92ee  |    3,1,1,0    |
//  0x7400  |   0x0   |   0x1  |      1  |      7  |  0x8800  |    3,1,1,1    |
//  0x75ff  |   0x1   |   0x2  |      1  |      7  |  0x8bff  |    3,1,1,1    |
//  0x5555  |   0x1   |   0x5  |      0  |      x  |  0xxxxx  |    x,x,x,x    |
//  0x4444  |   0x0   |   0x4  |      0  |      x  |  0xxxxx  |    x,x,x,x    |
//  0x8888  |   0x0   |   0x8  |      1  |      8  |  0x9999  |    3,1,1,1    |
//  0x8889  |   0x1   |   0x8  |      1  |      a  |  0xc0cc  |    3,1,1,1    |
//  0x8888  |   0x0   |   0xb  |      1  |      b  |  0xcccc  |    3,1,1,0    |
//  0x8888  |   0x1   |   0xc  |      1  |      c  |  0xdd11  |    3,1,1,1    |
//  0xeeee  |   0x1   |   0x8  |      1  |      e  |  0x01dd  |    3,1,1,1    |
//  0xffff  |   0x1   |   0x8  |      1  |      f  |  0x13ff  |    3,1,1,0    |
//  0x8888  |   0x1   |   0xf  |      0  |      x  |  0xxxxx  |    x,x,x,x    |
//  0x8848  |   0x0   |   0x8  |      0  |      x  |  0xxxxx  |    x,x,x,x    |
//  0x2333  |   0x0   |   0x8  |      0  |      x  |  0xxxxx  |    x,x,x,x    |
//  0x1551  |   0x0   |   0x0  |      0  |      x  |  0xxxxx  |    x,x,x,x    |


wire [19:0]             s_test_va_31_12 [25:0];
wire [9:0]              s_test_asid     [25:0];
wire                    s_test_found    [25:0];
wire [ 3:0]             s_test_index    [25:0];
wire [PALEN - 13 : 0]   s_test_ppn      [25:0];
wire [1:0]              s_test_plv      [25:0];
wire [1:0]              s_test_mat      [25:0];
wire                    s_test_d        [25:0];
wire                    s_test_v        [25:0];

assign s_test_va_31_12[ 0] = {19'h0000, 1'h0};
assign s_test_va_31_12[ 1] = {19'h0000, 1'h1};
assign s_test_va_31_12[ 2] = {19'h0000, 1'h1};
assign s_test_va_31_12[ 3] = {19'h1111, 1'h1};
assign s_test_va_31_12[ 4] = {19'h1111, 1'h0};
assign s_test_va_31_12[ 5] = {19'h1111, 1'h0};
assign s_test_va_31_12[ 6] = {19'h2222, 1'h0};
assign s_test_va_31_12[ 7] = {19'h3333, 1'h0};
assign s_test_va_31_12[ 8] = {19'h67ff, 1'h0};
assign s_test_va_31_12[ 9] = {19'h6400, 1'h1};
assign s_test_va_31_12[10] = {19'h6666, 1'h0};
assign s_test_va_31_12[11] = {19'h7777, 1'h0};
assign s_test_va_31_12[12] = {19'h7400, 1'h0};
assign s_test_va_31_12[13] = {19'h75ff, 1'h1};
assign s_test_va_31_12[14] = {19'h5555, 1'h1};
assign s_test_va_31_12[15] = {19'h4444, 1'h0};
assign s_test_va_31_12[16] = {19'h8888, 1'h0};
assign s_test_va_31_12[17] = {19'h8889, 1'h1};
assign s_test_va_31_12[18] = {19'h8888, 1'h0};
assign s_test_va_31_12[19] = {19'h8888, 1'h1};
assign s_test_va_31_12[20] = {19'heeee, 1'h1};
assign s_test_va_31_12[21] = {19'hffff, 1'h1};
assign s_test_va_31_12[22] = {19'h8888, 1'h1};
assign s_test_va_31_12[23] = {19'h8848, 1'h0};
assign s_test_va_31_12[24] = {19'h2333, 1'h0};
assign s_test_va_31_12[25] = {19'h1551, 1'h0};

assign s_test_asid[ 0] = 10'h0;
assign s_test_asid[ 1] = 10'h0;
assign s_test_asid[ 2] = 10'h1;
assign s_test_asid[ 3] = 10'h0;
assign s_test_asid[ 4] = 10'h0;
assign s_test_asid[ 5] = 10'h1;
assign s_test_asid[ 6] = 10'h2;
assign s_test_asid[ 7] = 10'h3;
assign s_test_asid[ 8] = 10'h6;
assign s_test_asid[ 9] = 10'h6;
assign s_test_asid[10] = 10'h7;
assign s_test_asid[11] = 10'h0;
assign s_test_asid[12] = 10'h1;
assign s_test_asid[13] = 10'h2;
assign s_test_asid[14] = 10'h5;
assign s_test_asid[15] = 10'h4;
assign s_test_asid[16] = 10'h8;
assign s_test_asid[17] = 10'h8;
assign s_test_asid[18] = 10'hb;
assign s_test_asid[19] = 10'hc;
assign s_test_asid[20] = 10'h8;
assign s_test_asid[21] = 10'h8;
assign s_test_asid[22] = 10'hf;
assign s_test_asid[23] = 10'h8;
assign s_test_asid[24] = 10'h8;
assign s_test_asid[25] = 10'h0;

assign s_test_found[ 0] = 1'h1;
assign s_test_found[ 1] = 1'h1;
assign s_test_found[ 2] = 1'h0;
assign s_test_found[ 3] = 1'h1;
assign s_test_found[ 4] = 1'h1;
assign s_test_found[ 5] = 1'h1;
assign s_test_found[ 6] = 1'h0;
assign s_test_found[ 7] = 1'h0;
assign s_test_found[ 8] = 1'h1;
assign s_test_found[ 9] = 1'h1;
assign s_test_found[10] = 1'h0;
assign s_test_found[11] = 1'h1;
assign s_test_found[12] = 1'h1;
assign s_test_found[13] = 1'h1;
assign s_test_found[14] = 1'h0;
assign s_test_found[15] = 1'h0;
assign s_test_found[16] = 1'h1;
assign s_test_found[17] = 1'h1;
assign s_test_found[18] = 1'h1;
assign s_test_found[19] = 1'h1;
assign s_test_found[20] = 1'h1;
assign s_test_found[21] = 1'h1;
assign s_test_found[22] = 1'h0;
assign s_test_found[23] = 1'h0;
assign s_test_found[24] = 1'h0;
assign s_test_found[25] = 1'h0;

assign s_test_index[ 0] = 4'h0;
assign s_test_index[ 1] = 4'h0;
assign s_test_index[ 2] = 4'hx;
assign s_test_index[ 3] = 4'h1;
assign s_test_index[ 4] = 4'h1;
assign s_test_index[ 5] = 4'h1;
assign s_test_index[ 6] = 4'hx;
assign s_test_index[ 7] = 4'hx;
assign s_test_index[ 8] = 4'h6;
assign s_test_index[ 9] = 4'h6;
assign s_test_index[10] = 4'hx;
assign s_test_index[11] = 4'h7;
assign s_test_index[12] = 4'h7;
assign s_test_index[13] = 4'h7;
assign s_test_index[14] = 4'hx;
assign s_test_index[15] = 4'hx;
assign s_test_index[16] = 4'h8;
assign s_test_index[17] = 4'ha;
assign s_test_index[18] = 4'hb;
assign s_test_index[19] = 4'hc;
assign s_test_index[20] = 4'he;
assign s_test_index[21] = 4'hf;
assign s_test_index[22] = 4'hx;
assign s_test_index[23] = 4'hx;
assign s_test_index[24] = 4'hx;
assign s_test_index[25] = 4'hx;

assign s_test_ppn[ 0] = 20'h1111;
assign s_test_ppn[ 1] = 20'h2022;
assign s_test_ppn[ 2] = 20'hxxxx;
assign s_test_ppn[ 3] = 20'h3033;
assign s_test_ppn[ 4] = 20'h2222;
assign s_test_ppn[ 5] = 20'h2222;
assign s_test_ppn[ 6] = 20'hxxxx;
assign s_test_ppn[ 7] = 20'hxxxx;
assign s_test_ppn[ 8] = 20'h8bfe;
assign s_test_ppn[ 9] = 20'h7001;
assign s_test_ppn[10] = 20'hxxxx;
assign s_test_ppn[11] = 20'h92ee;
assign s_test_ppn[12] = 20'h8800;
assign s_test_ppn[13] = 20'h8bff;
assign s_test_ppn[14] = 20'hxxxx;
assign s_test_ppn[15] = 20'hxxxx;
assign s_test_ppn[16] = 20'h9999;
assign s_test_ppn[17] = 20'hc0cc;
assign s_test_ppn[18] = 20'hcccc;
assign s_test_ppn[19] = 20'hdd11;
assign s_test_ppn[20] = 20'h01dd;
assign s_test_ppn[21] = 20'h13ff;
assign s_test_ppn[22] = 20'hxxxx;
assign s_test_ppn[23] = 20'hxxxx;
assign s_test_ppn[24] = 20'hxxxx;
assign s_test_ppn[25] = 20'hxxxx;

assign s_test_plv[ 0] = 2'h3;
assign s_test_plv[ 1] = 2'h3;
assign s_test_plv[ 2] = 2'hx;
assign s_test_plv[ 3] = 2'h3;
assign s_test_plv[ 4] = 2'h3;
assign s_test_plv[ 5] = 2'h3;
assign s_test_plv[ 6] = 2'hx;
assign s_test_plv[ 7] = 2'hx;
assign s_test_plv[ 8] = 2'h3;
assign s_test_plv[ 9] = 2'h3;
assign s_test_plv[10] = 2'hx;
assign s_test_plv[11] = 2'h3;
assign s_test_plv[12] = 2'h3;
assign s_test_plv[13] = 2'h3;
assign s_test_plv[14] = 2'hx;
assign s_test_plv[15] = 2'hx;
assign s_test_plv[16] = 2'h3;
assign s_test_plv[17] = 2'h3;
assign s_test_plv[18] = 2'h3;
assign s_test_plv[19] = 2'h3;
assign s_test_plv[20] = 2'h3;
assign s_test_plv[21] = 2'h3;
assign s_test_plv[22] = 2'hx;
assign s_test_plv[23] = 2'hx;
assign s_test_plv[24] = 2'hx;
assign s_test_plv[25] = 2'hx;

assign s_test_mat[ 0] = 3'h1;
assign s_test_mat[ 1] = 3'h1;
assign s_test_mat[ 2] = 3'hx;
assign s_test_mat[ 3] = 3'h1;
assign s_test_mat[ 4] = 3'h1;
assign s_test_mat[ 5] = 3'h1;
assign s_test_mat[ 6] = 3'hx;
assign s_test_mat[ 7] = 3'hx;
assign s_test_mat[ 8] = 3'h1;
assign s_test_mat[ 9] = 3'h1;
assign s_test_mat[10] = 3'hx;
assign s_test_mat[11] = 3'h1;
assign s_test_mat[12] = 3'h1;
assign s_test_mat[13] = 3'h1;
assign s_test_mat[14] = 3'hx;
assign s_test_mat[15] = 3'hx;
assign s_test_mat[16] = 3'h1;
assign s_test_mat[17] = 3'h1;
assign s_test_mat[18] = 3'h1;
assign s_test_mat[19] = 3'h1;
assign s_test_mat[20] = 3'h1;
assign s_test_mat[21] = 3'h1;
assign s_test_mat[22] = 3'hx;
assign s_test_mat[23] = 3'hx;
assign s_test_mat[24] = 3'hx;
assign s_test_mat[25] = 3'hx;

assign s_test_d[ 0] = 3'h1;
assign s_test_d[ 1] = 3'h1;
assign s_test_d[ 2] = 3'hx;
assign s_test_d[ 3] = 3'h1;
assign s_test_d[ 4] = 3'h1;
assign s_test_d[ 5] = 3'h1;
assign s_test_d[ 6] = 3'hx;
assign s_test_d[ 7] = 3'hx;
assign s_test_d[ 8] = 3'h1;
assign s_test_d[ 9] = 3'h1;
assign s_test_d[10] = 3'hx;
assign s_test_d[11] = 3'h1;
assign s_test_d[12] = 3'h1;
assign s_test_d[13] = 3'h1;
assign s_test_d[14] = 3'hx;
assign s_test_d[15] = 3'hx;
assign s_test_d[16] = 3'h1;
assign s_test_d[17] = 3'h1;
assign s_test_d[18] = 3'h1;
assign s_test_d[19] = 3'h1;
assign s_test_d[20] = 3'h1;
assign s_test_d[21] = 3'h1;
assign s_test_d[22] = 3'hx;
assign s_test_d[23] = 3'hx;
assign s_test_d[24] = 3'hx;
assign s_test_d[25] = 3'hx;

assign s_test_v[ 0] = 3'h1;
assign s_test_v[ 1] = 3'h1;
assign s_test_v[ 2] = 3'hx;
assign s_test_v[ 3] = 3'h0;
assign s_test_v[ 4] = 3'h1;
assign s_test_v[ 5] = 3'h1;
assign s_test_v[ 6] = 3'hx;
assign s_test_v[ 7] = 3'hx;
assign s_test_v[ 8] = 3'h1;
assign s_test_v[ 9] = 3'h0;
assign s_test_v[10] = 3'hx;
assign s_test_v[11] = 3'h0;
assign s_test_v[12] = 3'h1;
assign s_test_v[13] = 3'h1;
assign s_test_v[14] = 3'hx;
assign s_test_v[15] = 3'hx;
assign s_test_v[16] = 3'h1;
assign s_test_v[17] = 3'h1;
assign s_test_v[18] = 3'h0;
assign s_test_v[19] = 3'h1;
assign s_test_v[20] = 3'h1;
assign s_test_v[21] = 3'h0;
assign s_test_v[22] = 3'hx;
assign s_test_v[23] = 3'hx;
assign s_test_v[24] = 3'hx;
assign s_test_v[25] = 3'hx;
// write
always @(posedge clk_g) begin
    if(~resetn) begin
        tlb_w_test_ok <= 1'b0;
        tlb_w_cnt <= 4'b0;
    end
    else if(tlb_w_cnt==4'hf) begin
        tlb_w_test_ok <= 1'b1;
    end
    else if(~tlb_w_test_ok && wait_1s) begin
        tlb_w_cnt <= tlb_w_cnt + 1;
    end
end

// read
always @(posedge clk_g) begin
    if(~resetn) begin
        tlb_r_test_ok <= 1'b0;
        tlb_r_cnt <= 4'b0;
    end
    else if(tlb_r_cnt==4'hf && ~r_error) begin
        tlb_r_test_ok <= 1'b1;
    end
    else if(tlb_w_test_ok && ~tlb_r_test_ok && ~test_error && ~r_error && wait_1s) begin
        tlb_r_cnt <= tlb_r_cnt + 1;
    end
end

// search
always @(posedge clk_g) begin
    if(~resetn) begin
        tlb_s_test_ok <= 1'b0;
        tlb_s_cnt <= 4'b0;
    end
    else if(tlb_s_cnt==4'hc && ~s0_error && ~s1_error) begin
        tlb_s_test_ok <= 1'b1;
    end
    else if(tlb_w_test_ok && ~tlb_s_test_ok && ~test_error && ~s0_error && ~s1_error && wait_1s) begin
        tlb_s_cnt <= tlb_s_cnt + 1;
    end
end

assign we = ~tlb_w_test_ok;
assign w_index = tlb_w_cnt;
assign w_vppn  = tlb_vppn [tlb_w_cnt];
assign w_ps    = tlb_ps   [tlb_w_cnt];
assign w_g     = tlb_g    [tlb_w_cnt];
assign w_asid  = tlb_asid [tlb_w_cnt];
assign w_e     = tlb_e    [tlb_w_cnt];
assign w_ppn0  = tlb_ppn0 [tlb_w_cnt];
assign w_plv0  = tlb_plv0 [tlb_w_cnt];
assign w_mat0  = tlb_mat0 [tlb_w_cnt];
assign w_d0    = tlb_d0   [tlb_w_cnt];
assign w_v0    = tlb_v0   [tlb_w_cnt];
assign w_ppn1  = tlb_ppn1 [tlb_w_cnt];
assign w_plv1  = tlb_plv1 [tlb_w_cnt];
assign w_mat1  = tlb_mat1 [tlb_w_cnt];
assign w_d1    = tlb_d1   [tlb_w_cnt];
assign w_v1    = tlb_v1   [tlb_w_cnt];

assign r_index = tlb_r_cnt;
assign r_error =        
                (r_vppn  != tlb_vppn [tlb_w_cnt])|
                (r_ps    != tlb_ps   [tlb_w_cnt])|
                (r_g     != tlb_g    [tlb_w_cnt])|
                (r_asid  != tlb_asid [tlb_w_cnt])|
                (r_e     != tlb_e    [tlb_w_cnt])|
                (r_ppn0  != tlb_ppn0 [tlb_w_cnt])|
                (r_plv0  != tlb_plv0 [tlb_w_cnt])|
                (r_mat0  != tlb_mat0 [tlb_w_cnt])|
                (r_d0    != tlb_d0   [tlb_w_cnt])|
                (r_v0    != tlb_v0   [tlb_w_cnt])|
                (r_ppn1  != tlb_ppn1 [tlb_w_cnt])|
                (r_plv1  != tlb_plv1 [tlb_w_cnt])|
                (r_mat1  != tlb_mat1 [tlb_w_cnt])|
                (r_d1    != tlb_d1   [tlb_w_cnt])|
                (r_v1    != tlb_v1   [tlb_w_cnt]);

wire [4:0] s0_test_id,s1_test_id;
assign s0_test_id = {tlb_s_cnt,1'b0};
assign s1_test_id = {tlb_s_cnt,1'b1};

assign s0_va_31_12     = s_test_va_31_12[s0_test_id];
assign s0_asid     = s_test_asid[s0_test_id];
assign s1_va_31_12     = s_test_va_31_12[s1_test_id];
assign s1_asid     = s_test_asid[s1_test_id];

assign s0_error = (s_test_found[s0_test_id] ^ s0_found) || (s_test_found[s0_test_id] && (
                ~s0_found                             |
                (s0_index != s_test_index[s0_test_id])|
                (s0_ppn   != s_test_ppn  [s0_test_id])|
                (s0_plv   != s_test_plv  [s0_test_id])|
                (s0_mat   != s_test_mat  [s0_test_id])|
                (s0_d     != s_test_d    [s0_test_id])|
                (s0_v     != s_test_v    [s0_test_id])));
                   
assign s1_error = (s_test_found[s1_test_id] ^ s1_found) || (s_test_found[s1_test_id] && (
                ~s1_found                             |
                (s1_index != s_test_index[s1_test_id])|
                (s1_ppn   != s_test_ppn  [s1_test_id])|
                (s1_plv   != s_test_plv  [s1_test_id])|
                (s1_mat   != s_test_mat  [s1_test_id])|
                (s1_d     != s_test_d    [s1_test_id])|
                (s1_v     != s_test_v    [s1_test_id])));
                   
always @(posedge clk_g) begin
    if(~resetn) begin
        test_error <= 1'b0;
    end
    else if(tlb_w_test_ok && ~tlb_r_test_ok && r_error) begin
        test_error <= 1'b1;
    end
    else if(tlb_w_test_ok && ~tlb_s_test_ok && (s0_error || s1_error)) begin
        test_error <= 1'b1;
    end
end

reg [19:0] count;
always @(posedge clk_g)
begin
    if(!resetn)
    begin
        count <= 20'd0;
    end
    else
    begin
        count <= count + 1'b1;
    end
end
//scan data
reg [3:0] scan_data;
always @ ( posedge clk_g )  
begin
    if ( !resetn )
    begin
        scan_data <= 32'd0;  
        num_csn   <= 8'b1111_1111;
    end
    else
    begin
        case(count[19:17])
            3'b000 : scan_data <= {3'b0,s1_test_id[4]};
            3'b001 : scan_data <= s1_test_id[3:0];
            3'b010 : scan_data <= {3'b0,s0_test_id[4]};
            3'b011 : scan_data <= s0_test_id[3:0];
            3'b100 : scan_data <= 4'b0;
            3'b101 : scan_data <= tlb_r_cnt;
            3'b110 : scan_data <= 4'b0;
            3'b111 : scan_data <= tlb_w_cnt;
        endcase

        case(count[19:17])
            3'b000 : num_csn <= 8'b0111_1111;
            3'b001 : num_csn <= 8'b1011_1111;
            3'b010 : num_csn <= 8'b1101_1111;
            3'b011 : num_csn <= 8'b1110_1111;
            3'b100 : num_csn <= 8'b1111_0111;
            3'b101 : num_csn <= 8'b1111_1011;
            3'b110 : num_csn <= 8'b1111_1101;
            3'b111 : num_csn <= 8'b1111_1110;
        endcase
    end
end

always @(posedge clk_g)
begin
    if ( !resetn )
    begin
        num_a_g <= 7'b0000000;
    end
    else
    begin
        case ( scan_data )
            4'd0 : num_a_g <= 7'b1111110;   //0
            4'd1 : num_a_g <= 7'b0110000;   //1
            4'd2 : num_a_g <= 7'b1101101;   //2
            4'd3 : num_a_g <= 7'b1111001;   //3
            4'd4 : num_a_g <= 7'b0110011;   //4
            4'd5 : num_a_g <= 7'b1011011;   //5
            4'd6 : num_a_g <= 7'b1011111;   //6
            4'd7 : num_a_g <= 7'b1110000;   //7
            4'd8 : num_a_g <= 7'b1111111;   //8
            4'd9 : num_a_g <= 7'b1111011;   //9
            4'd10: num_a_g <= 7'b1110111;   //a
            4'd11: num_a_g <= 7'b0011111;   //b
            4'd12: num_a_g <= 7'b1001110;   //c
            4'd13: num_a_g <= 7'b0111101;   //d
            4'd14: num_a_g <= 7'b1001111;   //e
            4'd15: num_a_g <= 7'b1000111;   //f
        endcase
    end
end

assign led = {~test_error,12'hfff,~tlb_w_test_ok,~tlb_r_test_ok,~tlb_s_test_ok};

endmodule
